using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using Common;

using Common.Utilities;
using Common.Utilities.Dispatcher;
using Common.Utilities.Documents;
using Workflows.Components;
using Workflows.Components.DALC;
using Workflows.Diagrams.Properties;
using Northwoods.Go;

namespace Workflows.Diagrams
{
    /// <summary>
    /// control that holds design view/doc
    /// </summary>
    public partial class WorkflowDesignControl2 : UserControl
    {
        #region events
        public event UpdateProperty UpdatePropertyEvent;
        public event UpdateTitle UpdateTitleEvent;
        public event UpdateStatus UpdateStatusEvent;
        #endregion

        #region fields
        private bool _Dirty = false;
        private WorkflowDesign _WfDesign;
        private ComponentEditorManager _EditorManager;
        #endregion

        #region init
        /// <summary>
        /// 
        /// </summary>
        public WorkflowDesignControl2()
        {
            InitializeComponent();
            this._Dirty = false;
            this._WfDesign = new WorkflowDesign();
            //this._WfDesign.OnPropertyChangedEvent +=new OnPropertyChanged(HandlesWorkflowNameChanged);
            this.InitDesignDocumentSettings();
        }

        //private void HandlesWorkflowNameChanged(object owner, string propName)
        //{
        //    PropertyInfo propInfo = owner.GetType().GetProperty(propName);
        //    object propValue = propInfo.GetValue(owner, null);
        //    if ((propValue != null) && (this.UpdateTitleEvent != null))
        //    {
        //        this.UpdateTitleEvent(propValue.ToString());
        //    }
        //}

        /// <summary>
        /// initialized with file path
        /// </summary>
        /// <param name="designFilePath"></param>
        public WorkflowDesignControl2(string designFilePath)
        {
            InitializeComponent();
            this._Dirty = false;
            this._WfDesign = new WorkflowDesign(designFilePath);
            //this._WfDesign.OnPropertyChangedEvent += new OnPropertyChanged(HandlesWorkflowNameChanged);
            this.InitDesignDocumentSettings();

            //List<ActivityNode> activityNodes = this.GetAllActivityNodes();
            //if (activityNodes != null && activityNodes.Count > 0)
            //{
            //    foreach (ActivityNode activityNode in activityNodes)
            //    {
            //        activityNode.OnActivityNodeOpened +=new ActivityNodeOpened(activityNode_OnActivityNodeOpened);
            //    }
            //}
        }

        //private string GetTempFilePath(string fileExtension)
        //{
        //    string appFolderPath = Common.FileUtil.GetWindowsAppFolderPath();
        //    string tempFolderPath = appFolderPath + "\\temp";
        //    if (!System.IO.Directory.Exists(tempFolderPath))
        //    {
        //        System.IO.Directory.CreateDirectory(tempFolderPath);
        //    }
        //    string tempFileName = DateTime.Now.Ticks.ToString() + fileExtension;
        //    return System.IO.Path.Combine(tempFolderPath, tempFileName);
        //}

        private void InitDesignDocumentSettings()
        {
            // doc type
            this.gow_Workflow.Document = new ProcessDocument();
            this.gow_Workflow.Document.MaintainsPartID = true;
            this.gow_Workflow.Document.Changed += new GoChangedEventHandler(Document_Changed);

            // view
            this.gow_Workflow.NewLinkClass = typeof(FlowLink);
            this.gow_Workflow.ReplaceMouseTool(typeof(GoToolDragging), new SubGraphDraggingTool(this.gow_Workflow));
            this.gow_Workflow.ReplaceMouseTool(typeof(GoToolLinkingNew), new RestrictedLinkingNewTool(this.gow_Workflow));
            this.gow_Workflow.ReplaceMouseTool(typeof(GoToolRelinking), new RestrictedRelinkingTool(this.gow_Workflow));

            // turn on undo manager
            this.gow_Workflow.Document.UndoManager = new GoUndoManager();

            // root
            this.gow_Workflow.Document.UserObject = this._WfDesign;

            // register view event handler 
            this.gow_Workflow.BackgroundSingleClicked += new GoInputEventHandler(gow_Workflow_BackgroundSingleClicked);
            this.gow_Workflow.ObjectEdited += new GoSelectionEventHandler(gow_Workflow_ObjectEdited);
            this.gow_Workflow.LinkCreated += new GoSelectionEventHandler(gow_Workflow_LinkCreated);
            this.gow_Workflow.ObjectDoubleClicked += new GoObjectEventHandler(gow_Workflow_ObjectDoubleClicked);
            this.gow_Workflow.ObjectSingleClicked += new GoObjectEventHandler(gow_Workflow_ObjectSingleClicked);
            // drag-drop 
            //this.gow_Workflow.ExternalObjectsDropped += new GoInputEventHandler(gow_Workflow_ExternalObjectsDropped);
            this.gow_Workflow.DragDrop += new DragEventHandler(gow_Workflow_DragDrop);
        }

        private void WorkflowDesignControl2_Load(object sender, EventArgs e)
        {
            this._EditorManager=new ComponentEditorManager();
        }
        #endregion

        #region properties
        /// <summary>
        /// determine if continue closing when dirty
        /// </summary>
        public bool IsDirty
        {
            get
            {
                return this._Dirty;
            }
            set
            {
                this._Dirty = value;
            }
        }

        /// <summary>
        /// file path (binary)
        /// </summary>
        public string DesignDiagramFilePath
        {
            get
            {
                return this._WfDesign.DesignDocumentFilePath;
            }
            set
            {
                this._WfDesign.DesignDocumentFilePath = value;
            }
        }

        /// <summary>
        /// name
        /// </summary>
        public string WorkflowName
        {
            get
            {
                return this._WfDesign.WorkflowName;
            }
        }

        /// <summary>
        /// view
        /// </summary>
        public GoView DesignView
        {
            get
            {
                return this.gow_Workflow;
            }
        }

        /// <summary>
        /// meta data
        /// </summary>
        public WorkflowDesign WorkflowDesign
        {
            get
            {
                this._WfDesign.Clear();
                List<WorkflowComponentBase> wfComponents = this.GetAllComponents();
                if (wfComponents != null && wfComponents.Count > 0)
                {
                    foreach (WorkflowComponentBase component in wfComponents)
                    {
                        this._WfDesign.AddComponent(component);
                    }
                }
                List<Connector> connectors = this.GetAllConnectors();
                if (connectors != null)
                {
                    foreach (Connector connector in connectors)
                    {
                        this._WfDesign.AddConnector(connector);
                    }
                }
                return this._WfDesign;
            }
        }
        #endregion

        #region naming service
        private string GetComponentName(WorkflowComponentBase newWfComponent)
        {
            string componentName = newWfComponent.ComponentName;
            int index = 0;
            if (this.gow_Workflow.Document.Count > 0)
            {
                GoLayerCollectionObjectEnumerator goEnum = this.gow_Workflow.Document.GetEnumerator();
                while (goEnum.MoveNext())
                {
                    GoObject goObj = goEnum.Current;

                    if (goObj.GetType() == typeof (ActivityNode))
                    {
                        ActivityNode activityNode = (ActivityNode) goObj;
                        object userObj = activityNode.UserObject;
                        if (userObj.GetType().IsSubclassOf(typeof(WorkflowComponentBase)))
                        {
                            WorkflowComponentBase wfComponent = (WorkflowComponentBase) userObj;
                            if (wfComponent.ComponentName.ToLower() ==
                                componentName.ToLower() + (index > 0 ? " " + index.ToString() : ""))
                            {
                                index += 1;
                            }
                        }
                    }
                    else if (goObj.GetType() == typeof (MultiPortSubGraph))
                    {
                        MultiPortSubGraph mpGraph = (MultiPortSubGraph) goObj;
                        if (!mpGraph.IsEmpty)
                        {
                            for (int i = 0; i < mpGraph.Count; i++)
                            {
                                GoObject childObj = mpGraph[i];
                                if (childObj.GetType() == typeof (ActivityNode))
                                {
                                    ActivityNode childActivityNode = (ActivityNode) childObj;
                                    WorkflowComponentBase wfComponent =
                                        childActivityNode.UserObject as WorkflowComponentBase;
                                    if (wfComponent != null)
                                    {
                                        if (wfComponent.ComponentName.ToLower() ==
                                            componentName.ToLower() + (index > 0 ? " " + index.ToString() : ""))
                                        {
                                            index += 1;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (index > 0)
                return componentName + " " + index.ToString();
            else
                return componentName;
        }
        #endregion

        #region view event handlers
        void gow_Workflow_ObjectSingleClicked(object sender, GoObjectEventArgs e)
        {
            if (this.gow_Workflow.Document.DefaultLayer.PickObject(e.DocPoint, true) != null)
            {
                GoObject goObj = this.gow_Workflow.Document.DefaultLayer.PickObject(e.DocPoint, true);
                if (goObj.GetType() == typeof(GoImage) && (goObj.Parent != null))
                {
                    goObj = goObj.Parent;
                }
                if (goObj.GetType() == typeof(ActivityNode))
                {
                    ActivityNode activityNode = (ActivityNode)goObj;
                    this.UpdateNodePosition(activityNode);
                    WorkflowComponentBase wfComponent = activityNode.UserObject as WorkflowComponentBase;
                    if (this.UpdatePropertyEvent != null)
                    {
                        this.UpdatePropertyEvent(wfComponent);
                    }
                }
                else if(goObj.GetType()==typeof(FlowLink))
                {
                    FlowLink link = (FlowLink) goObj;
                    Connector wfConnector = (Connector) link.UserObject;
                    if(this.UpdatePropertyEvent !=null)
                    {
                        this.UpdatePropertyEvent(wfConnector);
                    }
                }
            }
        }

        void gow_Workflow_ObjectDoubleClicked(object sender, GoObjectEventArgs e)
        {
            if (this.gow_Workflow.Document.DefaultLayer.PickObject(e.DocPoint, true) != null)
            {
                GoObject goObj = this.gow_Workflow.Document.DefaultLayer.PickObject(e.DocPoint, true);
                if (goObj.GetType() == typeof(GoImage) && goObj.Parent != null)
                {
                    goObj = goObj.Parent;
                }
                if (goObj.GetType() == typeof(ActivityNode))
                {
                    ActivityNode activityNode = (ActivityNode)goObj;
                    this.UpdateNodePosition(activityNode);
                    WorkflowComponentBase wfComponent = activityNode.UserObject as WorkflowComponentBase;
                    if (this.UpdatePropertyEvent != null)
                    {
                        this.UpdatePropertyEvent(wfComponent);
                    }
                    if (wfComponent != null && this._EditorManager.Editors.ContainsKey(wfComponent.GetType().FullName))
                    {
                        Type editorType1 = this._EditorManager.Editors[wfComponent.GetType().FullName];
                        IComponentEditor componentEditor = (IComponentEditor) Activator.CreateInstance(editorType1);
                        Form editorForm = (Form) componentEditor;
                        editorForm.Show(this.ParentForm);
                        // editorForm.Text = wfComponent.ComponentName + " Editor";
                        WorkflowComponentBase[] upstreamComponents = this.GetUpstreamWorkflowComponents(activityNode);
                        //componentEditor.UpstreamComponents = upstreamComponents;
                        InstructionBase instruction = wfComponent.Instruction;
                        List<GlobalVariable> gVars=new List<GlobalVariable>();
                        if(this._WfDesign.GlobalVariables !=null && this._WfDesign.GlobalVariables.Length>0)
                            gVars.AddRange(this._WfDesign.GlobalVariables);
                        instruction.BindToGlobalVariableValues(gVars);
                        componentEditor.LoadSettings(this._WfDesign.GlobalVariables, upstreamComponents, activityNode, wfComponent);
                        componentEditor.UpdateComponentSettingEvent += new UpdateComponentSettings(typeEditor_UpdateComponentSettingEvent);
                    }
                }
                else if(goObj.GetType()==typeof(FlowLink))
                {
                    FlowLink link = (FlowLink) goObj;
                    Connector wfConnector = (Connector) link.UserObject;
                    if(wfConnector !=null && link.FromNode !=null && link.ToNode !=null)
                    {
                        ActivityNode fromNode = (ActivityNode) link.FromNode;
                        ActivityNode toNode = (ActivityNode) link.ToNode;
                        WorkflowComponentBase fromComponent = (WorkflowComponentBase) fromNode.UserObject;
                        WorkflowComponentBase toComponent = (WorkflowComponentBase) toNode.UserObject;
                        DataPipeMapper dataPipeMapper=new DataPipeMapper();
                        string toPortName = string.Empty;
                        if(link.ToPort !=null && link.ToPort.GetType()==typeof(ActivityPort))
                        {
                            ActivityPort toActivityPort = (ActivityPort) link.ToPort;
                            Port port = (Port) toActivityPort.UserObject;
                            toPortName = port.DataName;
                        }
                        dataPipeMapper.SetDataPipe(link, wfConnector, toPortName, fromComponent,
                                                   toComponent);
                        dataPipeMapper.OnDataConverterUpdated += new DataConverterUpdated(dataPipeMapper_OnDataConverterUpdated);
                        if(wfConnector.FieldMappers !=null)
                        {
                            // DataConverterBase converter = (DataConverterBase) wfConnector.DataConverter;
                            dataPipeMapper.SetFieldMappers(wfConnector.FieldMappers);
                        }

                        dataPipeMapper.Show(this.ParentForm);
                    }
                }
            }
        }

        void dataPipeMapper_OnDataConverterUpdated(FlowLink link, Connector wfConnector, WorkflowComponentBase toComponent, List<CodeFieldMapper> fieldMappers)
        {
            // TODO: implement this update
            // throw new Exception("The method or operation is not implemented.");
            // DataConverterBase converter=new 
            wfConnector.FieldMappers = fieldMappers;
            link.UserObject = wfConnector;
            ConnectorType connectorType = (ConnectorType)link.FromPort.UserFlags;
            switch (connectorType)
            {
                case ConnectorType.Successful:
                    link.Pen.Color = Color.Green;
                    break;
                case ConnectorType.Failure:
                    link.Pen.Color = Color.Red;
                    break;
                case ConnectorType.Trigger:
                    link.Pen.Color = Color.Blue;
                    break;
                default:
                    link.Pen.Color = Color.Green;
                    break;
            }
            if(wfConnector.Filter !=null && wfConnector.Filter.Length>0)
            {
                this.UpdateConnectorImage(link,Resources.search_48x48);
            }
            else
            {
                this.UpdateConnectorImage(link,null);
            }

            ActivityNode toNode =(ActivityNode) link.ToNode;
            toNode.UserObject = toComponent;

            this.gow_Workflow.Refresh();
        }

        void gow_Workflow_LinkCreated(object sender, GoSelectionEventArgs e)
        {
            if (e.GoObject.GetType() == typeof(FlowLink))
            {
                FlowLink link = e.GoObject as FlowLink;
                if (link != null)
                {
                    if ((link.FromNode != null) && (link.ToNode != null))
                    {
                        GoObject fromNode = (GoObject)link.FromNode;
                        GoObject toNode = (GoObject) link.ToNode;
                        if ((fromNode.GetType() == typeof (ActivityNode)) && (toNode.GetType() == typeof (ActivityNode)))
                        {
                            ConnectorType connectorType = ConnectorType.Successful;
                            if (link.FromPort != null)
                            {
                                connectorType = (ConnectorType) link.FromPort.UserFlags;
                                switch (connectorType)
                                {
                                    case ConnectorType.Successful:
                                        link.Pen = new Pen(Color.Green, 2);
                                        break;
                                    case ConnectorType.Failure:
                                        link.Pen = new Pen(Color.Red, 2);
                                        break;
                                    case ConnectorType.Trigger:
                                        link.Pen = new Pen(Color.Blue, 2);
                                        break;
                                }
                            }

                            try
                            {
                                WorkflowComponentBase fromComponent =
                                    (WorkflowComponentBase) ((ActivityNode) fromNode).UserObject;
                                WorkflowComponentBase toComponent =
                                    (WorkflowComponentBase) ((ActivityNode) toNode).UserObject;
                                Connector wfConnector = new Connector();
                                wfConnector.ConnectorName = fromComponent.OutputName;
                                wfConnector.ConnectorType = connectorType;
                                wfConnector.FieldMappers = new List<CodeFieldMapper>();
                                wfConnector.FromComponentID = fromComponent.ComponentID;
                                wfConnector.ToComponentID = toComponent.ComponentID;
                                List<CodeFieldMapper> fieldMappers=new List<CodeFieldMapper>();

                                string inputDataNameForTgtComponent = ((Port)((ActivityPort)link.ToPort).UserObject).DataName;
                                Type inputTypeForTargetComponent = toComponent.Instruction.GetType();
                                //ProcessInputType inputType = toComponent.InputType;
                                //if (inputType.InputName == inputDataNameForTgtComponent)
                                //{
                                //    inputTypeForTargetComponent = inputType.DataType;
                                //}
                                if(connectorType!=ConnectorType.Failure && fromComponent.Output.GetType()==inputTypeForTargetComponent)
                                {
                                    CodeFieldMapper fieldMapper=new CodeFieldMapper();
                                    fieldMapper.AssignmentTransformation = string.Empty;
                                    fieldMapper.SrcComponentID = fromComponent.ComponentID;
                                    fieldMapper.SrcFieldName = string.Empty;
                                    fieldMapper.TgtComponentID = toComponent.ComponentID;
                                    fieldMapper.TgtFieldName = string.Empty;
                                    fieldMapper.TgtInputName = inputDataNameForTgtComponent;
                                    fieldMappers.Add(fieldMapper);
                                }
                                else if(connectorType==ConnectorType.Failure && inputTypeForTargetComponent==typeof(string))
                                {
                                    CodeFieldMapper fieldMapper = new CodeFieldMapper();
                                    fieldMapper.AssignmentTransformation = string.Empty;
                                    fieldMapper.SrcComponentID = fromComponent.ComponentID;
                                    fieldMapper.SrcFieldName = string.Empty;
                                    fieldMapper.TgtComponentID = toComponent.ComponentID;
                                    fieldMapper.TgtFieldName = string.Empty;
                                    fieldMapper.TgtInputName = inputDataNameForTgtComponent;
                                    fieldMappers.Add(fieldMapper);
                                }
                                wfConnector.FieldMappers = fieldMappers;
                                // fromComponent.OutputType

                                link.UserObject = wfConnector;
                                if(fieldMappers.Count>0)
                                {
                                    if (connectorType == ConnectorType.Failure)
                                    {
                                        link.Text = fromComponent.ErrorName;
                                    }
                                    else if (connectorType == ConnectorType.Successful)
                                    {
                                        link.Text = fromComponent.OutputName;
                                    }
                                    else
                                    {
                                        link.Text = fromComponent.OutputName;
                                    }

                                    this.UpdateLinkage(link);
                                }
                                else if (this.CanLink(fromComponent, toComponent))
                                {
                                    if (connectorType == ConnectorType.Failure)
                                    {
                                        link.Text = fromComponent.ErrorName;
                                    }
                                    else if (connectorType == ConnectorType.Successful)
                                    {
                                        link.Text = fromComponent.OutputName;
                                    }
                                    else
                                    {
                                        link.Text = fromComponent.OutputName;
                                    }

                                    this.UpdateLinkage(link);
                                }
                                else
                                {
                                    link.Pen.Color = Color.Orange;
                                    if (connectorType == ConnectorType.Failure)
                                    {
                                        link.Text = fromComponent.ErrorName;
                                    }
                                    else if (connectorType == ConnectorType.Successful)
                                    {
                                        link.Text = fromComponent.OutputName;
                                    }
                                    else
                                    {
                                        link.Text = fromComponent.OutputName;
                                    }

                                    this.UpdateLinkage(link);
                                    // this.gow_Workflow.Document.Remove(link);
                                }
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.Message, ex.Source);
                            }
                        }
                    }

                    link.RealLink.CalculateStroke();
                }
            }
        }

        void gow_Workflow_ObjectEdited(object sender, GoSelectionEventArgs e)
        {
            if (e.GoObject.GetType() == typeof(ActivityNode))
            {
                ActivityNode activityNode = (ActivityNode)e.GoObject;
                WorkflowComponentBase wfComponent = activityNode.UserObject as WorkflowComponentBase;
                if (wfComponent != null)
                {
                    // TODO:
                }
            }
            else if(e.GoObject.GetType()==typeof(GoText) && e.GoObject.Parent.GetType()==typeof(ActivityNode))
            {
                string newName = ((GoText)e.GoObject).Text;
                ActivityNode activityNode = (ActivityNode) e.GoObject.Parent;
                WorkflowComponentBase wfComponent = activityNode.UserObject as WorkflowComponentBase;
                if(wfComponent !=null)
                    wfComponent.ComponentName = newName;
            }
            this._Dirty = true;
        }

        void gow_Workflow_BackgroundSingleClicked(object sender, GoInputEventArgs e)
        {
            if (this.UpdatePropertyEvent != null)
            {
                this.UpdatePropertyEvent(this._WfDesign);
            }
        }

        private WorkflowComponentBase[] GetUpstreamWorkflowComponents(ActivityNode activityNode)
        {
            List<WorkflowComponentBase> wfComponents = new List<WorkflowComponentBase>();
            foreach (IGoLink srcLink in activityNode.SourceLinks)
            {
                GoObject obj = (GoObject)srcLink.FromNode;
                if ((obj != null) && (obj.GetType() == typeof(ActivityNode)))
                {
                    WorkflowComponentBase component = ((ActivityNode)obj).UserObject as WorkflowComponentBase;
                    if (component != null)
                    {
                        wfComponents.Add(component);
                    }
                }
            }

            if (wfComponents.Count > 0)
            {
                return wfComponents.ToArray();
            }
            else
            {
                return null;
            }
        }
        #endregion

        #region document event handler
        void Document_Changed(object sender, GoChangedEventArgs e)
        {
            if (e.GoObject != null && e.GoObject.GetType() == typeof(ActivityNode))
            {
                WorkflowComponentBase component = ((ActivityNode)e.GoObject).UserObject as WorkflowComponentBase;
                if (component != null)
                {
                    if (e.Hint == Northwoods.Go.GoLayer.InsertedObject)
                    {
                        this._WfDesign.AddComponent(component);
                    }
                    else if (e.Hint == GoLayer.RemovedObject)
                    {
                        this._WfDesign.RemoveComponent(component.ComponentID);
                    }
                    else if (e.Hint == GoLayer.ChangedObject)
                    {
                        this._WfDesign.UpdateComponent(component);
                    }
                }
            }
            this._Dirty = true;
        }
        #endregion

        #region drag-drop
        void gow_Workflow_DragDrop(object sender, DragEventArgs e)
        {
            if (this.ParentForm != null && this.ParentForm.GetType().GetInterface(typeof(IMainForm).Name) != null)
            {
                IMainForm mainForm = (IMainForm)this.ParentForm;
                WorkflowComponentBase wfComponent =
                    (WorkflowComponentBase) Activator.CreateInstance(mainForm.DraggedObject.GetType());

                if (wfComponent != null)
                {
                    ActivityNode activityNode = this.CreateActivityNode(wfComponent);
                    Point pos = new Point(e.X, e.Y);
                    Point viewPoint = this.gow_Workflow.PointToClient(pos);
                    activityNode.Position = viewPoint;
                    try
                    {
                        this.gow_Workflow.Document.Add(activityNode);
                        this.UpdateNodePosition(activityNode);
                        mainForm.DraggedObject = null;
                        this._Dirty = true;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    mainForm.DraggedObject = null;
                }
            }

            //if (this.ParentForm != null && this.ParentForm.GetType() == typeof(Main))
            //{
            //    Main mainForm = (Main)this.ParentForm;
            //    Type selectedToolItemType = mainForm.SelectedToolItemType;
            //    if (selectedToolItemType != null)
            //    {
            //        ActivityNode activityNode = this.CreateActivityNodeByType(selectedToolItemType);
            //        Point pos = new Point(e.X, e.Y);
            //        Point viewPoint = this.gow_Workflow.PointToClient(pos);
            //        activityNode.Position = viewPoint;
            //        try
            //        {
            //            this.gow_Workflow.Document.Add(activityNode);
            //            this.UpdateNodePosition(activityNode);
            //            mainForm.SelectedToolItemType = null;
            //        }
            //        catch (Exception ex)
            //        {
            //            WorkflowComponentBase component = activityNode.UserObject as WorkflowComponentBase;
            //            if (component != null)
            //                this._WfDesign.RemoveComponent(component.Guid);
            //            this.gow_Workflow.Document.Remove(activityNode);
            //            MessageBox.Show(ex.Message);
            //        }
            //        mainForm.SelectedToolItemType = null;    
            //    }
            //}
        }

        //void activityNode_OnActivityNodeOpened(ActivityNode activityNode)
        //{
        //    if (activityNode != null)
        //    {
        //        this.UpdateNodePosition(activityNode);
        //        WorkflowComponentBase wfComponent = activityNode.UserObject as WorkflowComponentBase;
        //        if (this.UpdatePropertyEvent != null)
        //        {
        //            this.UpdatePropertyEvent(wfComponent);
        //        }
        //        if (wfComponent != null && this._EditorManager.Editors.ContainsKey(wfComponent.GetType().FullName))
        //        {
        //            Type editorType1 = this._EditorManager.Editors[wfComponent.GetType().FullName];
        //            IComponentEditor componentEditor = (IComponentEditor)Activator.CreateInstance(editorType1);
        //            Form editorForm = (Form)componentEditor;
        //            editorForm.Show(this.ParentForm);
        //            // editorForm.Text = wfComponent.ComponentName + " Editor";
        //            WorkflowComponentBase[] upstreamComponents = this.GetUpstreamWorkflowComponents(activityNode);
        //            //componentEditor.UpstreamComponents = upstreamComponents;
        //            componentEditor.LoadSettings(this._WfDesign.GlobalVariables, upstreamComponents, activityNode, wfComponent);
        //            componentEditor.UpdateComponentSettingEvent += new UpdateComponentSettings(typeEditor_UpdateComponentSettingEvent);
        //        }
        //    }
        //}

        private ActivityNode CreateActivityNode(WorkflowComponentBase wfComponent)
        {
            ActivityNode activityNode = new ActivityNode();
            string componentName = this.GetComponentName(wfComponent);
            wfComponent.ComponentName = componentName;
            activityNode.InitializeActivity(wfComponent, componentName, wfComponent.Description);
            // activityNode.OnActivityNodeOpened += new ActivityNodeOpened(activityNode_OnActivityNodeOpened);
            return activityNode;
        }
        #endregion

        #region position
        private void UpdateNodePosition(ActivityNode activityNode)
        {
            if (activityNode.UserObject.GetType().IsSubclassOf(typeof(WorkflowComponentBase)))
            {
                WorkflowComponentBase wfComponent = (WorkflowComponentBase)activityNode.UserObject;
                wfComponent.X = activityNode.Left;
                wfComponent.Y = activityNode.Top;
                wfComponent.Width = activityNode.Width;
                wfComponent.Height = activityNode.Height;
                activityNode.UserObject = wfComponent;
                if (this.UpdatePropertyEvent != null)
                {
                    this.UpdatePropertyEvent(wfComponent);
                }
            }
        }
        #endregion

        #region dependency
        private void UpdateLinkage(FlowLink link)
        {
            Connector connector = null;
            if (link.UserObject != null && link.UserObject.GetType() == typeof(Connector))
            {
                connector = link.UserObject as Connector;
            }
            else
            {
                connector = new Connector();
            }
            if(connector !=null)
            {
                if (link.FromNode.GetType() == typeof(ActivityNode) && link.ToNode.GetType() == typeof(ActivityNode))
                {
                    ActivityNode fromNode = (ActivityNode)link.FromNode;
                    ActivityNode toNode = (ActivityNode)link.ToNode;
                    connector.ConnectorType = (ConnectorType)link.FromPort.UserFlags;
                    WorkflowComponentBase fromComponent = fromNode.UserObject as WorkflowComponentBase;
                    if (fromComponent != null)
                    {
                        connector.FromComponentID = fromComponent.ComponentID;
                    }
                    WorkflowComponentBase toComponent = toNode.UserObject as WorkflowComponentBase;
                    if (toComponent != null)
                    {
                        connector.ToComponentID = toComponent.ComponentID;
                        this.UpdateDependency(toNode);
                    }
                }
                link.UserObject = connector;
            }
            
        }

        private void UpdateDependency(ActivityNode targetNode)
        {
            List<Guid> dependency = new List<Guid>();
            WorkflowComponentBase wfCompoent = targetNode.UserObject as WorkflowComponentBase;
            if (wfCompoent != null)
            {
                if (targetNode.SourceLinks.Count > 0)
                {
                    List<Guid> dependencyGuids = new List<Guid>();
                    GoNodeLinkEnumerator goEnum = targetNode.SourceLinks.GetEnumerator();
                    while (goEnum.MoveNext())
                    {
                        IGoLink link = goEnum.Current;
                        if (link.GetType() == typeof(FlowLink))
                        {
                            FlowLink fLink = (FlowLink)link;
                            GoObject upstreamObj = (GoObject)fLink.FromNode;
                            if (upstreamObj.GetType() == typeof(ActivityNode))
                            {
                                WorkflowComponentBase wfComponent = ((ActivityNode)upstreamObj).UserObject as WorkflowComponentBase;
                                if (wfComponent != null)
                                {
                                    dependencyGuids.Add(wfComponent.ComponentID);
                                }
                            }
                        }
                    }

                    if (dependencyGuids.Count > 0)
                    {
                        for (int i = 0; i < dependencyGuids.Count; i++)
                        {
                            dependency.Add(dependencyGuids[i]);
                        }
                    }
                }
                wfCompoent.Dependency = dependency;
                if (this.UpdatePropertyEvent != null)
                {
                    this.UpdatePropertyEvent(wfCompoent);
                }
            }

        }
        #endregion

        #region type checking
        private bool CanLink(WorkflowComponentBase fromComponent, WorkflowComponentBase toComponent)
        {
            List<Type> acceptableDataTypes = new List<Type>();
            if (toComponent.Instruction !=null)
            {
                if (!acceptableDataTypes.Contains(toComponent.Instruction.GetType()))
                {
                    acceptableDataTypes.Add(toComponent.Instruction.GetType());
                }
            }

            Type dataType = Type.Missing.GetType();
            if (fromComponent != null)
            {
                dataType = fromComponent.Output.GetType();
            }

            if (acceptableDataTypes.Count > 0)
                return DataPipeTypeChecker.CanAccept(acceptableDataTypes.ToArray(), dataType);
            else 
                return true;
        }
        #endregion

        #region edit-update
        /// <summary>
        /// TODO: implement logic to sync wfDoc
        /// </summary>
        /// <param name="activityNode"></param>
        /// <param name="wfComponent"></param>
        void typeEditor_UpdateComponentSettingEvent(object activityNode, WorkflowComponentBase wfComponent)
        {
            if (activityNode.GetType() == typeof(ActivityNode))
            {
                ActivityNode parentNode = (ActivityNode)activityNode;
                if (wfComponent.GetType().IsSubclassOf(typeof(WorkflowTriggerBase)))
                {
                    this.UpdateTrigger(parentNode, (WorkflowTriggerBase)wfComponent);
                }
                else
                {
                    List<GlobalVariable> gVars = new List<GlobalVariable>();
                    if (this._WfDesign.GlobalVariables != null && this._WfDesign.GlobalVariables.Length > 0)
                        gVars.AddRange(this._WfDesign.GlobalVariables);
                    InstructionBase instruction = wfComponent.Instruction;
                    instruction.ReplaceWithGlobalVariableBindings(gVars);
                    this.UpdateComponent(parentNode, wfComponent);
                }
            }
        }

        private void UpdateTrigger(ActivityNode activityNode, WorkflowTriggerBase trigger)
        {
            activityNode.UserObject = trigger;
            if (this.UpdatePropertyEvent != null)
            {
                this.UpdatePropertyEvent(trigger);
            }
        }

        private void UpdateComponent(ActivityNode activityNode, WorkflowComponentBase wfComponent)
        {
            activityNode.UserObject = wfComponent;
            if (this.UpdatePropertyEvent != null)
            {
                this.UpdatePropertyEvent(wfComponent);
            }
        }
        #endregion

        #region Save
        /// <summary>
        /// save to default path
        /// </summary>
        public void Save()
        {
            this._WfDesign.Version = new Version(
                Math.Max(0, this._WfDesign.Version.Major),
                Math.Max(0, this._WfDesign.Version.Minor),
                Math.Max(0, this._WfDesign.Version.Build),
                Math.Max(0, this._WfDesign.Version.Revision) + 1);
            if (string.IsNullOrEmpty(this._WfDesign.DesignDocumentFilePath))
            {
                string appDataFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
                if (!Directory.Exists(appDataFolderPath))
                {
                    Directory.CreateDirectory(appDataFolderPath);
                }
                string designFolderPath = System.IO.Path.Combine(appDataFolderPath, "workflow design");
                System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(designFolderPath);
                if (!dirInfo.Exists)
                {
                    dirInfo.Create();
                }
                string designFilePath = System.IO.Path.Combine(designFolderPath,
                    (this._WfDesign.WorkflowName ?? "New workflow") +
                    ".wox");
                this._WfDesign.DesignDocumentFilePath = designFilePath;
            }
            string woxFilePath = this._WfDesign.DesignDocumentFilePath;
            this.SaveBinary(woxFilePath);
            string folderPath = Path.GetDirectoryName(this._WfDesign.DesignDocumentFilePath);
            string fileName = Path.GetFileNameWithoutExtension(this._WfDesign.DesignDocumentFilePath);
            string xmlFilePath = Path.Combine(folderPath, fileName + ".xml");
            this.SaveXml(xmlFilePath);
            string pngFilePath = Path.Combine(folderPath, fileName + ".png");
            this.SaveGraph(pngFilePath);
        }

        /// <summary>
        /// save to another place, but there is still a copy in default folder
        /// </summary>
        /// <param name="woxFilePath"></param>
        public void SaveAs(string woxFilePath)
        {
            this._WfDesign.DesignDocumentFilePath = woxFilePath;
            this.Save();
        }

        private void SaveXml(string xmlFilePath)
        {
            this._WfDesign.ModificationTime = DateTime.Now;
            this._WfDesign.IsLocked = false;
            this._WfDesign.CheckOutBy = string.Empty;
            this._WfDesign.CheckOutTime = TimeUtil.DbMinTime;
            this._WfDesign.Clear();
            List<WorkflowComponentBase> wfComponents = this.GetAllComponents();
            if (wfComponents != null && wfComponents.Count > 0)
            {
                foreach (WorkflowComponentBase component in wfComponents)
                {
                    this._WfDesign.AddComponent(component);
                }
            }
            List<Connector> connectors = this.GetAllConnectors();
            if (connectors != null)
            {
                foreach (Connector connector in connectors)
                {
                    this._WfDesign.AddConnector(connector);
                }
            }
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml("<WorkflowDesign></WorkflowDesign>");
            XmlNode root = xDoc.DocumentElement;
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "WorkflowGuid", this._WfDesign.WorkflowGuid.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "WorkflowName", this._WfDesign.WorkflowName);
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "Version", this._WfDesign.Version.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "CreationTime", this._WfDesign.CreationTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "ModificationTime", this._WfDesign.ModificationTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "Author", this._WfDesign.Author);
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "Description", this._WfDesign.Description);
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "FailureNotifyEmailAddress", this._WfDesign.FailureNotifyEmailAddress);
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "CheckOutBy", this._WfDesign.CheckOutBy);
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "CheckOutTime", this._WfDesign.CheckOutTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "IsLocked", this._WfDesign.IsLocked.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "FilePath", this._WfDesign.DesignDocumentFilePath);

            XmlNode componentRootNode = XmlDataUtil.AddElement(ref xDoc, root, "Components");
            if (this._WfDesign.Components != null && this._WfDesign.Components.Length > 0)
            {
                foreach (WorkflowComponentBase wfCom in this._WfDesign.Components)
                {
                    wfCom.Serialize(ref xDoc, ref componentRootNode);
                }
            }

            XmlNode connectorRootNode = XmlDataUtil.AddElement(ref xDoc, root, "Connectors");
            if (this._WfDesign.Connectors != null && this._WfDesign.Connectors.Length > 0)
            {
                foreach (Connector conn in this._WfDesign.Connectors)
                {
                    Connector.Serialize(ref xDoc, ref connectorRootNode, conn);
                }
            }

            XmlNode varRootNode = XmlDataUtil.AddElement(ref xDoc, root, "GlobalVariables");
            if (this._WfDesign.GlobalVariables != null && this._WfDesign.GlobalVariables.Length > 0)
            {
                foreach (GlobalVariable wfVar in this._WfDesign.GlobalVariables)
                {
                    XmlNode varNode = XmlDataUtil.AddElement(ref xDoc, varRootNode, "Variable");
                    XmlDataUtil.UpdateAttribute(ref xDoc, varNode, "VariableName", wfVar.VarName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, varNode, "DataType", ((int)wfVar.DataType).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, varNode, "VariableValue", wfVar.VarValue.ToString());
                }
            }
            
            xDoc.Save(xmlFilePath);
        }

        private void SaveBinary(string woxFilePath)
        {
            System.IO.Stream fileStream = null;
            try
            {
                fileStream = new System.IO.FileStream(woxFilePath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write);
                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                formatter.Serialize(fileStream, this.gow_Workflow.Document);
                fileStream.Flush();
                fileStream.Close();
                formatter = null;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, ex.Source);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream = null;
                }
            }
        }

        private void SaveGraph(string pngFilePath)
        {
            Bitmap img = this.gow_Workflow.GetBitmapFromCollection(this.gow_Workflow.Document);
            img.Save(pngFilePath, System.Drawing.Imaging.ImageFormat.Png);
        }
        #endregion

        #region Open
        /// <summary>
        /// open
        /// </summary>
        public void Open()
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "Workflow blueprints(*.wox)|*.wox|All files(*.*)|*.*";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                this.Open(dlg.FileName);
            }
        }

        /// <summary>
        /// open
        /// </summary>
        /// <param name="filePath"></param>
        public void Open(string filePath)
        {
            if (filePath.ToLower().EndsWith(".xml"))
                this.OpenDesignSettingFile(filePath);
            else
            {
                FileStream fileStream = null;
                try
                {
                    fileStream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);
                    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter =
                        new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                    this.gow_Workflow.Document = (ProcessDocument) formatter.Deserialize(fileStream);
                    fileStream.Flush();
                    fileStream.Close();
                    formatter = null;

                    this.UpdateWorkflowDesignImages();
                    if (this.gow_Workflow.Document.UserObject != null)
                    {
                        this._WfDesign = (WorkflowDesign) this.gow_Workflow.Document.UserObject;
                    }
                    this._WfDesign.DesignDocumentFilePath = filePath;
                    //List<ActivityNode> activityNodes = this.GetAllActivityNodes();
                    //if (activityNodes != null && activityNodes.Count > 0)
                    //{
                    //    foreach (ActivityNode activityNode in activityNodes)
                    //    {
                    //        activityNode.OnActivityNodeOpened += new ActivityNodeOpened(activityNode_OnActivityNodeOpened);
                    //    }
                    //}
                }
                catch (Exception ex)
                {
                    string xmlFilePath = Path.Combine(
                        Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath) + ".xml");
                    if (File.Exists(xmlFilePath))
                    {
                        this.OpenDesignSettingFile(xmlFilePath);
                    }
                    else
                    {
                        MessageBox.Show("Unable to open workflow design file: " + ex.Message);
                    }
                }
                finally
                {
                    if (fileStream != null)
                    {
                        fileStream = null;
                    }
                }
            }
            this._Dirty = false;
        }

        /// <summary>
        /// xml file is required when binary file is corrupted or
        /// version conflict
        /// </summary>
        /// <param name="xmlFilePath"></param>
        public void OpenDesignSettingFile(string xmlFilePath)
        {
            StringBuilder errorMsg=new StringBuilder();
            try
            {
                XmlDocument xDoc = new XmlDocument();
                xDoc.Load(xmlFilePath);
                WorkflowEngine engine = new WorkflowEngine();
                Dictionary<Guid, ActivityNode> activityNodes = new Dictionary<Guid, ActivityNode>();
                List<WorkflowComponentBase> wfComponents = engine.GetWorkflowComponents(xDoc);
                if(wfComponents !=null && wfComponents.Count>0)
                {
                    foreach(WorkflowComponentBase component in wfComponents)
                    {
                        ActivityNode activityNode = this.CreateActivityNode(component);
                        Point pos = new Point((int)component.X, (int)component.Y);
                        Point viewPoint = this.gow_Workflow.PointToClient(pos);
                        activityNode.Position = viewPoint;
                        try
                        {
                            this.gow_Workflow.Document.Add(activityNode);
                            this.UpdateNodePosition(activityNode);
                            activityNodes.Add(component.ComponentID, activityNode);
                        }
                        catch (Exception ex)
                        {
                            errorMsg.AppendLine(ex.Message);
                        }
                    }
                }
                List<Connector> connectors = engine.GetConnectors(xDoc);
                if(connectors !=null && connectors.Count>0)
                {
                    foreach(Connector connector in connectors)
                    {
                        ActivityNode fromNode = null;
                        ActivityNode toNode = null;
                        foreach(WorkflowComponentBase component in wfComponents)
                        {
                            if (component.ComponentID == connector.FromComponentID)
                                fromNode = activityNodes[connector.FromComponentID];
                            if (component.ComponentID == connector.ToComponentID)
                                toNode = activityNodes[connector.ToComponentID];
                        }
                        if (fromNode != null && toNode != null)
                        {
                            FlowLink link = new FlowLink();
                            link.UserObject = connector;
                            link.Label.Text = connector.ConnectorName;
                            switch (connector.ConnectorType)
                            {
                                case ConnectorType.Successful:
                                    link.Pen = new Pen(Color.Green, 2);
                                    link.FromPort = fromNode.OutboundPort;
                                    link.ToPort = toNode.InboundPort;
                                    break;
                                case ConnectorType.Failure:
                                    link.Pen = new Pen(Color.Red, 2);
                                    link.FromPort = fromNode.ErrorPort;
                                    link.ToPort = toNode.InboundPort;
                                    break;
                                case ConnectorType.Trigger:
                                    link.Pen = new Pen(Color.Blue, 2);
                                    link.FromPort = fromNode.OutboundPort;
                                    link.ToPort = toNode.InboundPort;
                                    break;
                            }

                            this.gow_Workflow.Document.Add(link);
                        }
                    }
                }

                this._WfDesign = this._WfDesign.ReadFromXml(xDoc);
                this.gow_Workflow.Document.UserObject = this._WfDesign;
                this.gow_Workflow.ScrollPage(-100, -100);
            }
            catch(Exception ex1)
            {
                errorMsg.AppendLine(ex1.Message);
            }

            if(errorMsg.Length>0)
            {
                MessageBox.Show(errorMsg.ToString());
            }
        }

        private void UpdateWorkflowDesignImages()
        {
            List<ActivityNode> activityNodes = this.GetAllActivityNodes();
            if (activityNodes != null && activityNodes.Count > 0)
            {
                foreach (ActivityNode activityNode in activityNodes)
                {
                    if (activityNode.UserObject != null && activityNode.UserObject.GetType().IsSubclassOf(typeof(WorkflowComponentBase)))
                    {
                        WorkflowComponentBase component = (WorkflowComponentBase)activityNode.UserObject;
                        this.UpdateActivityNodeImage(activityNode, component.ComponentImage);
                    }
                }
            }

            List<FlowLink> links = this.GetAllLinks();
            if(links !=null && links.Count>0)
            {
                foreach(FlowLink link in links)
                {
                    if(link.UserObject !=null && link.UserObject.GetType()==typeof(Connector))
                    {
                        Connector wfConnector = (Connector) link.UserObject;
                        if(wfConnector.Filter !=null)
                        {
                            Image filterImg = Resources.search_48x48;
                            this.UpdateConnectorImage(link,filterImg);
                        }
                    }
                }
            }
        }

        private void UpdateActivityNodeImage(ActivityNode activityNode, System.Drawing.Image img)
        {
            GoImage goImg = activityNode.Icon as GoImage;
            if (goImg != null)
            {
                goImg.Image = img;
                goImg.Size = new SizeF(48, 48);
            }
        }

        private void UpdateConnectorImage(FlowLink fLink, Image filterImg)
        {
            foreach(GoObject goObj in fLink)
            {
                if(goObj.GetType()==typeof(GoImage))
                {
                    GoImage img = (GoImage) goObj;
                    img.Image = filterImg;
                    if (filterImg != null)
                        img.Size = new SizeF(15, 15);
                    break;
                }
            }
        }
        #endregion

        #region sub-graph
        /// <summary>
        /// hide selected nodes in sub graph
        /// </summary>
        public void MakeSubGraph()
        {
            GoSelection selection = this.gow_Workflow.Selection;
            GoCollection collection = new GoCollection();
            GoLayer layer = null;
            GoObject commonObj = null;
            bool firstObj = true;
            if (selection != null && selection.Count > 0)
            {
                try
                {
                    foreach (GoObject obj in selection)
                    {
                        if (obj.GetType() == typeof(ActivityNode))
                        {
                            collection.Add(obj);
                        }
                        if (firstObj)
                        {
                            firstObj = false;
                            commonObj = obj;
                            layer = obj.Layer;
                        }
                        else
                        {
                            commonObj = GoObject.FindCommonParent(commonObj, obj);
                            if (!obj.Layer.Equals(layer))
                            {
                                MessageBox.Show("Can not mix layers of objects to be grouped into a subgraph");
                                return;
                            }
                        }
                    }

                    this.gow_Workflow.StartTransaction();
                    SubGraphDraggingTool draggingTool = (SubGraphDraggingTool)this.gow_Workflow.FindMouseTool(typeof(SubGraphDraggingTool));
                    GoSelection totalParts = draggingTool.ComputeEffectiveSelection(collection, true);
                    GoSubGraph subgraph = (MultiPortSubGraph)Activator.CreateInstance(typeof(MultiPortSubGraph));
                    subgraph.Text = "New group";
                    subgraph.Position = totalParts.Primary.Position;
                    if ((commonObj != null) && (commonObj.GetType() == typeof(GoSubGraph)))
                    {
                        ((GoSubGraph) commonObj).Add(subgraph);
                    }
                    else
                    {
                        this.gow_Workflow.Document.Add(subgraph);
                    }

                    subgraph.AddCollection(totalParts, true);
                    selection.Add(subgraph);

                    this.gow_Workflow.FinishTransaction("grouped subgraph");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, ex.Source);
                }
            }
        }

        /// <summary>
        /// expose hidden nodes within subgraph
        /// </summary>
        public void RemoveSubGraph()
        {
            if (this.gow_Workflow.Selection != null && this.gow_Workflow.Selection.Primary != null && (this.gow_Workflow.Selection.Primary.GetType() == typeof(MultiPortSubGraph)))
            {
                MultiPortSubGraph mpGraph = (MultiPortSubGraph)this.gow_Workflow.Selection.Primary;
                if (mpGraph == null)
                {
                    MessageBox.Show("Select a subgraph");
                    return;
                }

                try
                {
                    this.gow_Workflow.StartTransaction();
                    GoCollection collection = new GoCollection();
                    foreach (GoObject obj in mpGraph)
                    {
                        if (obj.Equals(mpGraph.Handle) || obj.Equals(mpGraph.Label) || obj.Equals(mpGraph.Port))
                        {
                            continue;
                        }

                        if (mpGraph.MultiPorts.Contains(obj))
                        {
                            continue;
                        }

                        GoLink tempLink = null;
                        if (obj.GetType() == typeof(GoLink))
                            tempLink = (GoLink)obj;
                        if ((tempLink ==null) || (!(tempLink.ToNode.GetType() == typeof(MultiPortSubGraph) || tempLink.FromNode.GetType()==typeof(MultiPortSubGraph))))
                        {
                            collection.Add(obj);
                        }
                    }

                    if ((mpGraph.Parent !=null) && (mpGraph.Parent.GetType() == typeof(MultiPortSubGraph)))
                    {
                        MultiPortSubGraph parent = (MultiPortSubGraph)mpGraph.Parent;
                        parent.AddCollection(collection, true);
                    }
                    else
                    {
                        GoLayer layer = mpGraph.Layer;
                        layer.AddCollection(collection, true);
                        GoLayer linkedLayer = layer.Document.LinksLayer;
                        foreach (GoObject goObj in collection)
                        {
                            IGoLink link = null;
                            if (!(goObj.GetType() == typeof(ActivityNode) || goObj.GetType() == typeof(MulticastDelegate)))
                            {
                                link = (IGoLink)goObj;
                            }
                            if (link != null)
                            {
                                if (!link.GoObject.Layer.Equals(linkedLayer))
                                {
                                    linkedLayer.Add(link.GoObject);
                                }
                            }
                        }
                    }

                    mpGraph.Remove();
                    GoSelection selection = this.gow_Workflow.Selection;
                    foreach (GoObject goObj in collection)
                    {
                        selection.Add(goObj);
                    }

                    this.gow_Workflow.FinishTransaction("Ungrouped subgraph");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, ex.Source);
                }
            }
        }
        #endregion

        #region edit
        /// <summary>
        /// 
        /// </summary>
        public void Undo()
        {
            this.gow_Workflow.Undo();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public GoCollection Copy()
        {
            GoSelection selection = this.gow_Workflow.Selection;
            GoCollection collection = new GoCollection();
            if (selection != null && selection.Count > 0)
            {
                foreach (GoObject obj in selection)
                {
                    if (obj.GetType() == typeof(ActivityNode))
                    {
                        ActivityNode copiedObj = (ActivityNode)obj.Copy();
                        WorkflowComponentBase wfComponent = (WorkflowComponentBase)copiedObj.UserObject;
                        if (wfComponent != null)
                        {
                            copiedObj.UserObject = wfComponent.Clone();
                            collection.Add(copiedObj);
                        }
                        else
                        {
                            collection.Add(obj.Copy());
                        }
                    }
                }
            }
            return collection;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="collection"></param>
        public void Paste(GoCollection collection)
        {
            if (collection != null && collection.Count > 0)
            {
                try
                {
                    this.gow_Workflow.StartTransaction();
                    foreach (GoObject obj in collection)
                    {
                        PointF newPos =new PointF(obj.Position.X +25, obj.Position.Y +25); 
                        this.gow_Workflow.Document.AddCopy(obj, newPos);
                    }
                    this.gow_Workflow.FinishTransaction(string.Format("Pasted {0} objects onto this design document", collection.Count));
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, ex.Source);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public GoCollection Cut()
        {
            GoSelection selection = this.gow_Workflow.Selection;
            GoCollection collection = new GoCollection();
            this.gow_Workflow.StartTransaction();
            if (selection != null && selection.Count > 0)
            {
                List<ActivityNode> activityNodesToRemove=new List<ActivityNode>();
                foreach (GoObject obj in selection)
                {
                    if (obj.GetType() == typeof(ActivityNode))
                    {
                        ActivityNode activityNode = (ActivityNode)obj;
                        WorkflowComponentBase wfComponent = activityNode.UserObject as WorkflowComponentBase;
                        if (wfComponent != null)
                        {
                            wfComponent.ComponentID = Guid.NewGuid();
                            activityNode.UserObject = wfComponent;
                        }
                        activityNodesToRemove.Add(activityNode);
                        collection.Add(activityNode);
                    }
                    else
                    {
                        this.gow_Workflow.Document.Remove(obj);
                        collection.Add(obj);
                    }
                }

                if(activityNodesToRemove.Count>0)
                {
                    foreach(ActivityNode activityNode in activityNodesToRemove)
                    {
                        this.gow_Workflow.Document.Remove(activityNode);
                    }
                }
            }
            this.gow_Workflow.FinishTransaction(string.Format("Total of {0} objects removed", collection.Count));
            return collection;
        }
        #endregion

        #region public methods
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public List<WorkflowComponentBase> GetAllComponents()
        {
            List<WorkflowComponentBase> wfComponents = new List<WorkflowComponentBase>();

            GoLayerCollectionObjectEnumerator goEnum = this.gow_Workflow.Document.GetEnumerator();
            while (goEnum.MoveNext())
            {
                GoObject obj = goEnum.Current;
                if (obj.GetType() == typeof(ActivityNode))
                {
                    ActivityNode activityNode = (ActivityNode)obj;
                    this.UpdateNodePosition(activityNode);
                    if (activityNode.UserObject.GetType().IsSubclassOf(typeof(WorkflowComponentBase)))
                    {
                        WorkflowComponentBase wfComponent = (WorkflowComponentBase)activityNode.UserObject;
                        wfComponent.X = activityNode.Position.X;
                        wfComponent.Y = activityNode.Position.Y;
                        wfComponents.Add(wfComponent);
                    }
                }
                else if (obj.GetType() == typeof(MultiPortSubGraph))
                {
                    MultiPortSubGraph mpGraph = (MultiPortSubGraph)obj;
                    if (!mpGraph.IsEmpty)
                    {
                        for (int i = 0; i < mpGraph.Count; i++)
                        {
                            GoObject goObj = mpGraph[i];
                            if (goObj.GetType() == typeof(ActivityNode))
                            {
                                ActivityNode activityNode = (ActivityNode)goObj;
                                this.UpdateNodePosition(activityNode);
                                if (activityNode.UserObject.GetType().IsSubclassOf(typeof(WorkflowComponentBase)))
                                {
                                    WorkflowComponentBase wfComponent = (WorkflowComponentBase)activityNode.UserObject;
                                    wfComponent.X = activityNode.Position.X;
                                    wfComponent.Y = activityNode.Position.Y;
                                    wfComponents.Add(wfComponent);
                                }
                            }
                        }
                    }
                }
            }
            return wfComponents;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public List<FlowLink> GetAllLinks()
        {
            List<FlowLink> links=new List<FlowLink>();
            GoLayerCollectionObjectEnumerator goEnum = this.gow_Workflow.Document.GetEnumerator();
            while (goEnum.MoveNext())
            {
                GoObject obj = goEnum.Current;
                if (obj.GetType() == typeof(FlowLink))
                {
                    FlowLink link = (FlowLink) obj;
                    links.Add(link);
                }
                else if (obj.GetType() == typeof(MultiPortSubGraph))
                {
                    MultiPortSubGraph mpGraph = (MultiPortSubGraph) obj;
                    if (!mpGraph.IsEmpty)
                    {
                        for (int i = 0; i < mpGraph.Count; i++)
                        {
                            GoObject goObj = mpGraph[i];
                            if (goObj.GetType() == typeof(FlowLink))
                            {
                                FlowLink link = (FlowLink) goObj;
                                links.Add(link);
                            }
                        }
                    }
                }
            }
            return links;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public List<Connector> GetAllConnectors()
        {
            List<Connector> connectors = new List<Connector>();
            GoLayerCollectionObjectEnumerator goEnum = this.gow_Workflow.Document.GetEnumerator();
            while (goEnum.MoveNext())
            {
                GoObject obj = goEnum.Current;
                if (obj.GetType() == typeof(FlowLink))
                {
                    FlowLink link = (FlowLink)obj;
                    this.UpdateLinkage(link);
                    Connector wfConnector = link.UserObject as Connector;
                    if (wfConnector != null)
                    {
                        connectors.Add(wfConnector);
                    }
                }
                else if (obj.GetType() == typeof(MultiPortSubGraph))
                {
                    MultiPortSubGraph mpGraph = (MultiPortSubGraph)obj;
                    if (!mpGraph.IsEmpty)
                    {
                        for (int i = 0; i < mpGraph.Count; i++)
                        {
                            GoObject goObj = mpGraph[i];
                            if (goObj.GetType() == typeof(FlowLink))
                            {
                                FlowLink link = (FlowLink)goObj;
                                this.UpdateLinkage(link);
                                Connector wfConnector = link.UserObject as Connector;
                                if (wfConnector != null)
                                {
                                    connectors.Add(wfConnector);
                                }
                            }
                        }
                    }
                }
            }
            return connectors;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public List<ActivityNode> GetAllActivityNodes()
        {
            List<ActivityNode> activityNodes = new List<ActivityNode>();
            GoLayerCollectionObjectEnumerator goEnum = this.gow_Workflow.Document.GetEnumerator();
            while (goEnum.MoveNext())
            {
                GoObject obj = goEnum.Current;
                if (obj.GetType() == typeof(ActivityNode))
                {
                    ActivityNode activityNode = (ActivityNode)obj;
                    activityNodes.Add(activityNode);
                }
                else if (obj.GetType() == typeof(MultiPortSubGraph))
                {
                    MultiPortSubGraph mpGraph = (MultiPortSubGraph)obj;
                    if (!mpGraph.IsEmpty)
                    {
                        for (int i = 0; i < mpGraph.Count; i++)
                        {
                            GoObject goObj = mpGraph[i];
                            if (goObj.GetType() == typeof(ActivityNode))
                            {
                                ActivityNode activityNode = (ActivityNode)goObj;
                                activityNodes.Add(activityNode);
                            }
                        }
                    }
                }
            }
            return activityNodes;
        }
        #endregion

    }
}
